package com.yunzhou.service.impl;

import com.yunzhou.entity.ForumArticle;
import com.yunzhou.entity.LikeRecord;
import com.yunzhou.entity.UserInfo;
import com.yunzhou.entity.UserMessage;
import com.yunzhou.enums.ForumArticleStatusEnum;
import com.yunzhou.enums.LikeRecordOpTypeEnum;
import com.yunzhou.enums.UserMessageStatusEnum;
import com.yunzhou.enums.UserMessageTypeEnum;
import com.yunzhou.mapper.ForumArticleMapper;
import com.yunzhou.mapper.LikeRecordMapper;
import com.yunzhou.mapper.UserMapper;
import com.yunzhou.mapper.UserMessageMapper;
import com.yunzhou.properties.ElasticSearchProperties;
import com.yunzhou.service.ForumArticleService;
import com.yunzhou.vo.HotForumArticleVO;
import java.time.LocalDateTime;

import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class ForumArticleServiceImpl implements ForumArticleService {

    @Autowired
    private ForumArticleMapper forumArticleMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LikeRecordMapper likeRecordMapper;
    @Autowired
    private UserMessageMapper userMessageMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 获取文章列表
    @Override
    public List<ForumArticle> getForumArticleList(Integer boardId, Integer parentBoardId, String boardName, String parentBoardName, Integer orderType, Integer pageNum, Integer pageSize) {
        return forumArticleMapper.getForumArticleList(boardId, parentBoardId, boardName, parentBoardName, orderType, pageNum, pageSize);
    }

    // 获取文章数
    @Override
    public Integer getForumArticleListTotal(Integer boardId, Integer parentBoardId, String boardName, String parentBoardName) {
        return forumArticleMapper.getForumArticleListTotal(boardId, parentBoardId, boardName, parentBoardName);
    }

    // 根据文章ID获取文章
    @Override
    public ForumArticle getForumArticleByArticleId(Long articleId) {
        ForumArticle forumArticle = forumArticleMapper.getForumArticleByArticleId(articleId);
        if (forumArticle == null) {
            throw new RuntimeException("当前文章未找到");
        }
        if (!forumArticle.getStatus().equals(ForumArticleStatusEnum.AUDIT.getStatus())) {
            throw new RuntimeException("当前文章 未通过审核 或 已被删除");
        }
        return forumArticle;
    }

    // 更新文章阅读数
    @Override
    @Transactional
    public void updateForumArticleReadCountByArticleId(Long articleId, Integer count) {
        while (true) {
            // 1. 查询商品信息
            // Product product = productMapper.selectProduct(productId);
            // int currentVersion = product.getVersion();

            // 2. 尝试增加数量
            // int rowsAffected = productMapper.increaseQuantity(productId, currentVersion);
            // if (rowsAffected == 1) {
            //     // 更新成功，跳出循环
            //     break;
            // }
            // 如果更新失败，说明版本号不一致，重试
            Integer rowAffected = forumArticleMapper.updateForumArticleReadCountByArticleId(articleId, count);
             if (rowAffected == 1) {
                 // 更新成功，跳出循环
                 break;
             }
        }
    }

    // 文章点赞
    @Override
    @Transactional
    public void doArticleLike(Long articleId, Long userId) {
        // 0、通过文章ID获取文章的属性
        ForumArticle forumArticle = forumArticleMapper.getForumArticleByArticleId(articleId);
        if (forumArticle == null) {
            throw new RuntimeException("文章不存在");
        }
        if (!forumArticle.getStatus().equals(ForumArticleStatusEnum.AUDIT.getStatus())) {
            throw new RuntimeException("当前文章 未通过审核 或 已被删除");
        }

        // 0、通过当前登录的用户ID获取当前登录的用户的信息
        UserInfo userInfo = userMapper.selectByUserId(userId);

        // ----------------------------------------------------------------------------------
        // 判断是否需插入一条点赞记录
        LikeRecord likeRecord = new LikeRecord();
        likeRecord.setOpType(LikeRecordOpTypeEnum.ARTICLE_LIKE.getOpType()); // 文章点赞
        likeRecord.setObjectId(articleId);
        likeRecord.setUserId(userId);
        likeRecord.setCreateTime(LocalDateTime.now());
        likeRecord.setAuthorUserId(forumArticle.getUserId());

        if (likeRecordMapper.getLikeRecordByObjectIdAndUserIdAndOpType(articleId, userId, LikeRecordOpTypeEnum.ARTICLE_LIKE.getOpType()) != null) {
            // 1、若用户已经点赞过当前文章，则删除掉表中记录，且文章点赞数-1
            likeRecordMapper.deleteLikeRecordByObjectIdAndUserIdAndOpType(articleId, userId, LikeRecordOpTypeEnum.ARTICLE_LIKE.getOpType());
            forumArticleMapper.updateForumArticleLikeCountByArticleId(articleId, -1);
            System.out.println(userInfo.getUserId()+"取消用户点赞完成");
        } else {
            // 2、若用户未点赞过当前文章，则insert一条点赞记录，并使文章点赞数量+1
            likeRecordMapper.insert(likeRecord);
            forumArticleMapper.updateForumArticleLikeCountByArticleId(articleId, 1);
            System.out.println(userInfo.getUserId()+"用户点赞完成");
        }

        // 4、还需在用户消息表中新增一条消息
        // 若用户已经点过赞了，则不会insert一条消息
        UserMessage userMessage = new UserMessage();
        userMessage.setReceivedUserId(forumArticle.getUserId());
        userMessage.setArticleId(articleId);
        userMessage.setArticleTitle(forumArticle.getTitle());
        userMessage.setCommentId(null); // 因为这是文章点赞，不涉及评论点赞
        userMessage.setSendUserId(userId); // 当前登录的用户点的赞
        userMessage.setSendNickname(userInfo.getNickname());
        userMessage.setMessageType(UserMessageTypeEnum.ARTICLE_LIKE.getMessageType()); // 2：文章点赞
        userMessage.setStatus(UserMessageStatusEnum.NO_READ.getStatus()); // 默认未读
        userMessage.setCreateTime(LocalDateTime.now());
        if (userMessageMapper.getUserMessageByArticleIdAndSendUserId(articleId, userId, UserMessageTypeEnum.ARTICLE_LIKE.getMessageType()) == null) {
            // 若未找到点赞记录，则说明当前用户是第一次为该文章点赞，可以插入一条记录
            userMessageMapper.insert(userMessage);
        }
    }

    // 新增文章
    @Override
    public void insert(ForumArticle forumArticle) {
        forumArticleMapper.insert(forumArticle);
    }

    // 更新文章
    @Override
    public void update(ForumArticle forumArticle) {
        forumArticleMapper.update(forumArticle);
    }

    // 根据用户ID获取发表文章
    @Override
    public List<ForumArticle> getForumArticleListByUserId(Long userId, Integer orderType, Integer pageNum, Integer pageSize) {
        return forumArticleMapper.getForumArticleListByUserId(userId,orderType,pageNum,pageSize);
    }

    // 根据用户ID获取发表文章数
    @Override
    public Integer getPostCountByUserId(Long userId) {
        return forumArticleMapper.getPostCountByUserId(userId);
    }

    // 根据文章ID删除文章
    public void deleteForumArticleByArticleId(Long articleId){
        forumArticleMapper.deleteForumArticleByArticleId(articleId);
    }

    // 生成热点文章，存储到redis中
    @Override
    // @Scheduled(cron = "0/10 * * * * ?") // 每10s执行一次
    @Scheduled(cron = "0 0 0 ? * SUN")  // 每周日的午夜（即每天的00:00）执行任务。
    public void getHotArticletoRedis() {
        // 1、先获取数据库中前7天发表的文章
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 计算7天前的时间点
        LocalDateTime sevenDaysAgo = now.minusDays(7);

        List<ForumArticle> hotArticleList = forumArticleMapper.getHotArticle(sevenDaysAgo);

        // 2、计算分值
        List<HotForumArticleVO> list = new ArrayList<>();
        if (hotArticleList != null && hotArticleList.size() > 0){
            for (ForumArticle article : hotArticleList) {
                HotForumArticleVO hotForumArticleVO = new HotForumArticleVO();
                BeanUtils.copyProperties(article, hotForumArticleVO);

                // 求分 score = 阅读数 + 点赞数*3 + 评论数*5
                Integer score = 0;
                if (article.getReadCount() != null){
                    score += article.getReadCount();
                }
                if (article.getLikeCount() != null){
                    score += article.getLikeCount() * 3;
                }
                if (article.getCommentCount() != null){
                    score += article.getCommentCount() * 5;
                }
                hotForumArticleVO.setScore(score);
                list.add(hotForumArticleVO);

            }
        }

//        for (HotForumArticleVO item : list) {
//            // System.out.println("处理后的热点文章" + item.getTitle());
//        }

        // 3、将前10条热门文章存储到redis中
        list = list.stream().sorted(Comparator.comparing(HotForumArticleVO::getScore).reversed()).collect(Collectors.toList());
        if (list.size() > 10){
            list = list.subList(0, 10);
        }
        // 往redis中存储一个键值对  StringRedisTemplate
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        // 设置过期时间 30天
        operations.set("hot_article_list", list,30, TimeUnit.DAYS);

    }

}
